#include "sixbitstring.h"
#include <QDebug>

using namespace ns_yht;

SixBitString::SixBitString(const QByteArray &str)
{
    byte_length = str.length();

    for (int i = 0; i < byte_length; i++)
    {
        bitBytes[i] = to_6bit(str[i]);
    }
}

QChar SixBitString::to_6bit(QChar c)
{
    if (c < 0x30)
        return static_cast<QChar>(-1);
    if (c > 0x77)
        return static_cast<QChar>(-1);
    if ((0x57 < c) && (c < 0x60))
        return static_cast<QChar>(-1);

    int cp = c.toLatin1();
    cp += 0x28;

    if (cp > 0x80)
        cp += 0x20;
    else
        cp += 0x28;

    return QChar(cp & 0x3f);
}

int SixBitString::getInt(int start, int len, bool signed_flag)
{
    int acc = 0;
    int s0p = start - 1; // to zero base

    int cp, cx, c0, cs;

    for (int i = 0; i < len; i++)
    {
        acc = acc << 1;
        cp = (s0p + i) / 6;
        cx = bitBytes[cp].toLatin1(); // what if cp >= byte_length?
        cs = 5 - ((s0p + i) % 6);
        c0 = (cx >> (5 - ((s0p + i) % 6))) & 1;
        if (i == 0 && signed_flag && c0) // if signed value and first bit is 1, pad with 1's
            acc = ~acc;
        acc |= c0;
    }

    return acc;
}

QByteArray SixBitString::getStr(int start, int bit_len)
{
    // char temp_str[85];
    // char *temp_str = dest;
    QByteArray dest;

    char acc = 0;
    int s0p = start - 1; // to zero base

    // int k = 0;
    int cp, cx, c0, cs;

    int i = 0;
    while (i < bit_len)
    {
        acc = 0;
        for (int j = 0; j < 6; j++)
        {
            acc = acc << 1;
            cp = (s0p + i) / 6;
            if (cp >= byte_length || cp < 0)
                return "";
            cx = bitBytes[cp].toLatin1(); // what if cp >= byte_length?
            cs = 5 - ((s0p + i) % 6);
            c0 = (cx >> (5 - ((s0p + i) % 6))) & 1;
            acc |= c0;

            i++;
        }

        // temp_str[k] = (char)(acc & 0x3f);
        if (acc == 0)
            break;
        if (acc < 32)
            dest.append((acc & 0x3f) + 0x40);
        else
            dest.append((acc & 0x3f));
        // k++;
    }

    // for (int i = 0; i < code.length(); i += 6)
    //{
    //     int id = code.mid(i, 6).toInt(nullptr, 2);
    //     if (id == 0)break;
    //     result = result + SIX_BIT_ASCII[id];
    // }

    return dest.trimmed();
}

int SixBitString::getBitCount()
{
    return byte_length * 6;
}

double SixBitString::getLat(int start, int len)
{
    double divisor;
    switch (len)
    {
    case 17:
        divisor = 600.0;
        break;
    case 24:
        divisor = 60000.0; // 1/1000th minute
        break;
    case 27:
        divisor = 600000.;
        break;
    default:
        // std::cerr << "Unsupported point AIS size: " << point_size << std::endl;
        // assert(false);
        return 91;
    }

    int acc = getInt(start, len, true);
    if (acc == 0x3412140)
        return 91;

    return acc / divisor;
}

double SixBitString::getLon(int start, int len)
{
    double divisor;
    switch (len)
    {
    case 18:
        divisor = 600.0;
        break;
    case 25:
        divisor = 60000.0; // 1/1000th minute
        break;
    case 28:
        divisor = 600000.;
        break;
    default:
        // std::cerr << "Unsupported point AIS size: " << point_size << std::endl;
        // assert(false);
        return 181;
    }

    int acc = getInt(start, len, true);
    if (acc == 0x6791AC0)
        return 181;
    return acc / divisor;
}